/* EMS CPC-PCI card handling
 *
 * This still is old-style handling
 * walking through the list of PCI devices manually
 * This has to be replaced by pci_register_driver()
 * and the pci_probe function()
 */

/* This is shown by /sbin/lspci -vv -nn:
 
EMS_PCI V1.0
05:05.0 Network controller [0280]: Siemens AG Eicon Diva 2.02 compatible passive ISDN card [110a:2104] (rev 01)
        Subsystem: Device [ff00:0000]
        Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0
        Interrupt: pin A routed to IRQ 20
        NUMA node: 0
        Region 0: Memory at febff000 (32-bit, non-prefetchable) [size=4K]
        Region 1: Memory at febfe000 (32-bit, non-prefetchable) [size=4K]
        Capabilities: [40] Power Management version 1
                Flags: PMEClk+ DSI+ D1+ D2- AuxCurrent=0mA PME(D0-,D1+,D2-,D3hot-,D3cold-)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-


EMS_PCI V2
05:05.0 Bridge [0680]: PLX Technology, Inc. PCI9030 32-bit 33MHz PCI <-> IOBus Bridge [10b5:9030] (rev 01)
        Subsystem: PLX Technology, Inc. Device [10b5:4000]
        Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx-
        Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Interrupt: pin A routed to IRQ 20
        NUMA node: 0
        Region 0: Memory at febffc00 (32-bit, non-prefetchable) [size=128]
        Region 2: Memory at febfe000 (32-bit, non-prefetchable) [size=4K]
        Capabilities: [40] Power Management version 1
                Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot-,D3cold-)
                Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
        Capabilities: [48] CompactPCI hot-swap 
        Capabilities: [4c] Vital Product Data
pcilib: sysfs_read_vpd: read failed: Input/output error
                Not readable
 */

/* use it for pr_info() and consorts */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include "defs.h"
#include <linux/pci.h>


# ifndef CONFIG_PCI
#   error "trying to compile a PCI driver for a kernel without CONFIG_PCI"
# endif

#define EMS_PCI_V1_MAX_CHAN 2
#define EMS_PCI_V2_MAX_CHAN 4
/* even if the old EMS_PCI has only two channels */
#define EMS_PCI_MAX_CHAN    EMS_PCI_V2_MAX_CHAN

#define EMS_PCI_CAN_CLOCK (16000000 / 2)
#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
#define EMS_PCI_CAN_CTRL_SIZE   0x200 /* memory size for each controller */


/*
 * PSB4610 PITA-2 bridge control registers
 */
#define PITA2_ICR           0x00	/* Interrupt Control Register */
#define PITA2_ICR_INT0      0x00000002	/* [RC] INT0 Active/Clear */
#define PITA2_ICR_INT0_EN   0x00020000	/* [RW] Enable INT0 */

#define PITA2_MISC          0x1c	/* Miscellaneous Register */
#define PITA2_MISC_CONFIG   0x04000000	/* Multiplexed parallel interface */


/*
 * Register definitions for the PLX 9030
 */
#define PLX_ICSR            0x4c   /* Interrupt Control/Status register */
#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */
#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */
#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */
#define PLX_ICSR_ENA_CLR    (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \
			     PLX_ICSR_LINTI1_CLR)

/*
 * In the CDR register, you should set CBP to 1.
 * You will probably also want to set the clock divider value to 7
 * (meaning direct oscillator output) because the second SJA1000 chip
 * is driven by the first one CLKOUT output.
 */
#define EMS_PCI_CDR             (CDR_CBP | CDR_CLKOUT_MASK)

#define EMS_PCI_V1_BASE_BAR     1
#define EMS_PCI_V1_CONF_SIZE    4096 /* size of PITA control area */
#define EMS_PCI_V2_BASE_BAR     2
#define EMS_PCI_V2_CONF_SIZE    128 /* size of PLX control area */
#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
#define EMS_PCI_CAN_CTRL_SIZE   0x200 /* memory size for each controller */

#define EMS_PCI_BASE_SIZE	4096 /* size of controller area */



#define PCI_BASE_ADDRESS0(dev) (dev->resource[0].start)
#define PCI_BASE_ADDRESS1(dev) (dev->resource[1].start)
#define PCI_BASE_ADDRESS2(dev) (dev->resource[2].start)
#define PCI_BASE_ADDRESS3(dev) (dev->resource[3].start)

/* used for storing the global pci control register address */
void __iomem *can_pitapci_control[MAX_CHANNELS];
/* storing the version number, some handling is different */
int ems_card_version[MAX_CHANNELS];


/* In all implementations so far we worked with the struct canregs
 * in register access macros. This workedt on the old V1 EMS PCI
 * wit an offset of 4 bytes for each register as defined in this special
 * struct canregs, and this worked also for the V2 with a standard struct with
 * no dummy bytes in between the registers as all byte registers are here placed
 * in a byte array.
 * Now with version 2 of the EMS CPC_PCI2 driver, both boards should be
 * supported with one source code and both boards should be used at one runtime
 * meaning you can have an old an d a new board running at the same time.
 *
 * Now we need another access to the registers. We will try replacing the macros
 * by functions, defined here:
 */

void CAN_OUT(int minor, int adr, unsigned char v)
{
unsigned char *ptr = (unsigned char *)can_iobase[minor];

    if(ems_card_version[minor] == 1) {
	ptr += (4 * adr);
    } else {
	ptr += adr;
    }
    writeb(v, ptr);
}

u8 CAN_IN(int minor, int adr)
{
u8 *ptr = can_iobase[minor];

    if(ems_card_version[minor] == 1) {
	ptr += (4 * adr);
    } else {
	ptr += adr;
    }
    return readb(ptr);
}

void  CAN_SET(int minor, int adr, int mask)
{
u8 *ptr = can_iobase[minor];

    if(ems_card_version[minor] == 1) {
	ptr += (4 * adr);
    } else {
	ptr += adr;
    }
    writeb(readb(ptr) | (mask), ptr);
}

void  CAN_RESET(int minor, int adr, int mask)
{
u8 *ptr = can_iobase[minor];

    if(ems_card_version[minor] == 1) {
	ptr += (4 * adr);
    } else {
	ptr += adr;
    }
    writeb(readb(ptr) & ~(mask), ptr);
}


/* i is the number of overall CAN controllers collected so far
 * from all boards */
static int register_v2_cpcpci(struct pci_dev *pdev, int i)
{
void __iomem *ptr;		/* ptr to PCI control registers*/
void __iomem *cptr;		/* ptr to start of CAN control registers*/
int j;				/* loop through possible CAN controllers */
int minor = -1;			/* to make DBGIN() happy */

    DBGIN();

    /* dev, bar, size */
    ptr		= pci_iomap(pdev, 0, 128);
    cptr	= pci_iomap(pdev, 2, 2048);


    // pr_info("cptr= %p\n", cptr);

    /* look for a CAN controllers starting at 0x400 */
    for (j = 0; j < EMS_PCI_MAX_CHAN; j++) {

	/* The CAN controller is in region 2 */
	if (controller_available(cptr 
		    +  EMS_PCI_CAN_BASE_OFFSET
		    + (EMS_PCI_CAN_CTRL_SIZE * j), 1)) {
	    pr_info("\tCAN controller %d. at pos %d\n", i + 1, j);
	    if (i > MAX_CHANNELS) {
		    pr_err("only %d devices supported\n", MAX_CHANNELS);
		    break; /* the devices scan loop */
	    }
	/*
	   in this case, we can have four CAN controllers at region 2:
	   x + 400, x + 600, x + 800, x + a00 
	*/
	    proc_iomodel[i] = 'm';
	    IRQ[i]	    = pdev->irq;
	    proc_clock	    = EMS_PCI_CAN_CLOCK;

#ifdef __x86_64__
	    proc_base[i]
		= (upointer_t)cptr
		    +  EMS_PCI_CAN_BASE_OFFSET
		    + (EMS_PCI_CAN_CTRL_SIZE * i);
	    /* code may be enabled when developing/debugging code
	    = (upointer_t)ioremap(PCI_BASE_ADDRESS2(pdev)
		    +  EMS_PCI_CAN_BASE_OFFSET
		    + (EMS_PCI_CAN_CTRL_SIZE * i), EMS_PCI_CAN_CTRL_SIZE);

	    pr_err("  Base %llx/%lld",
	    (long long unsigned)proc_base[i],
	    (long long unsigned)proc_base[i]);
	    pr_err("  Base %lx", proc_base[i]);
	    */
#else
	    proc_base[i]
	    = (unsigned long)ioremap(PCI_BASE_ADDRESS2(pdev)
		    +  EMS_PCI_CAN_BASE_OFFSET
		    + (EMS_PCI_CAN_CTRL_SIZE * i), EMS_PCI_CAN_CTRL_SIZE);
	    /* pr_err("  Base %lx", proc_base[i]); */
#endif
	    /* reset the CAN controller(s)
	    CAN_OUT(minor, canmode, CAN_RESET_REQUEST);
	     */
	    writeb(CAN_RESET_REQUEST, (void __iomem *)proc_base[i]);

	    /* store pointer to control reg of PCI bridge */
	    can_pitapci_control[i] = ptr;
	    i++;
	}
    }
    /* enable IRQ in PLX 9030 */

    // writel(PLX9030_ICR_ENABLE_IRQ0, ptr + PLX9030_ICR);
    writel(PLX_ICSR_ENA_CLR,  ptr + PLX_ICSR);

    DBGOUT();
    return i;	/* returns last CAN controller number found */
}


#if 0
/* reset both CAN controllers on the EMS-Wünsche CPC-PCI Board */
/* writing to the control range at BAR1 of the PCI board */
static void reset_CPC_PCI(unsigned long address)
{
unsigned long ptr = (unsigned long)ioremap(address, 32);

	writeb(0x01, (void __iomem *)ptr);
}
#endif

/* check if the pci device is a valid old style CPC-PCI and
 * get all the hardware information needed and fill in the board information
 * the device itself is already registered  pci_enable_device().
 * i is the number of overall CAN controllers collected so far
 * from all boards
 */
static int register_v1_cpcpci(struct pci_dev *pdev, int i)
{
int minor = -1;			/* to make DBGIN() happy */
void __iomem *ptr;		/* ptr to PCI PITA control registers*/
void __iomem *cptr;		/* ptr to start of CAN control registers*/
int j;				/* loop through possible CAN controllers */

    DBGIN();

    // pr_err("int candev ist %d", i);

    /* dev, bar, size */
    ptr		= pci_iomap(pdev, 0, EMS_PCI_V1_CONF_SIZE);
    cptr	= pci_iomap(pdev, EMS_PCI_V1_BASE_BAR, EMS_PCI_BASE_SIZE);

    /* enable memory access */
    /* pr_info("write to pita\n"); */
    writel(PITA2_MISC_CONFIG, ptr + PITA2_MISC);
    can_pitapci_control[i] = ptr;
    /* Check for unique EMS CAN signature 
    * PCI_BASE_ADDRESS1:
    * at address 0 are some EMS control registers
    * at address 0x400 the first controller area
    * at address 0x600 the second controller area
    * registers are read as 32bit
    *
    * at adress 0 we can verify the card
    * 0x55 0xaa 0x01 0xcb
    */
    {
	void __iomem *sigptr; /* ptr to EMS signature  */
	unsigned long signature = 0;
	sigptr = (void __iomem *)ioremap(PCI_BASE_ADDRESS1(pdev), 256);
	signature =
		(readb(sigptr)      << 24)
		+ (readb(sigptr +  4) << 16)
		+ (readb(sigptr +  8) <<  8)
		+  readb(sigptr + 12);
	pr_info("\tsignature  %lx\n", signature);
	if (0x55aa01cb != signature) {
		pr_info(" wrong signature -- no EMS CPC-PCI board\n");
		return -ENODEV;
	}
    }
#if 0
    /* claim the board for this driver */
    i = pci_request_region(pdev, 0, "can4linux ctrl");
    if(i != 0 ) {
	return -1;
    }
    i = pci_request_region(pdev, EMS_PCI_V1_BASE_BAR, "can4linux");
    if(i != 0 ) {
	return -1;
    }
#endif

    /* enable interrupts Int_0 */
    /* write to PITAs ICR register */
    writel(PITA2_ICR_INT0_EN,
    (void __iomem *)can_pitapci_control[i] + PITA2_ICR);

    /* Request board reset */
    /* done in the controller loop 
      writeb(0, cptr);
      */


    /* look for a CAN controllers starting at 0x400 */
    for (j = 0; j < EMS_PCI_MAX_CHAN; j++) {
	if (controller_available(cptr
		    +  EMS_PCI_CAN_BASE_OFFSET
		    + (EMS_PCI_CAN_CTRL_SIZE * j), 4)) {
	    pr_info("\tCAN controller %d at pos %d\n", i + 1, j);
	    if (i > MAX_CHANNELS) {
		    pr_info("only %d devices supported\n", MAX_CHANNELS);
		    return i; /* the devices scan loop */
	    }
	    /* we found one CAN controller at this location
	     * register it in the proc_ entries*/
	    ems_card_version[i] = 1;
	    proc_iomodel[i] = 'm';
	    IRQ[i]	    = pdev->irq;
	    proc_clock	    = EMS_PCI_CAN_CLOCK;

	    proc_base[i] = (upointer_t)(cptr
		    +  EMS_PCI_CAN_BASE_OFFSET
		    + (EMS_PCI_CAN_CTRL_SIZE * i));
	    /* always use the ptr from the first controller (j == 0) on this
	     * board */ 
	    can_pitapci_control[i] = can_pitapci_control[i - j];

	    /* reset the CAN controller */
	    writeb(CAN_RESET_REQUEST, (void __iomem *)proc_base[i]);
	    i++;

	} else {
		pr_info(" CAN: NO at pos %d\n", j);
		;
	}
    }

    // pr_err("int next candev is %d", i);
    DBGOUT();
    return i;
}

static int pcimod_scan(void)
{
struct	pci_dev *pdev;
int	candev;				/* number of devices found */
int	minor = -1;			/* to make DBGIN() happy */

	DBGIN();

	pdev = NULL;
	candev = 0;
	for_each_pci_dev(pdev) {
		if (pdev->vendor == PCI_VENDOR_ID_PLX
			&& pdev->device == PCI_DEVICE_ID_PLX_9030) {

			pr_info("\tfound EMS PCI board V2: %s", pci_name(pdev));
			pr_info("\tSubsystem Vendor 0x%0x\n", pdev->subsystem_vendor);
			pr_info("\tSubsystem Device 0x%0x\n", pdev->subsystem_device);
			/* reading delivers 0x10b5, 0x4000 */
			if (pci_enable_device(pdev))
				continue;
			else {
			int cnt;
			cnt = register_v2_cpcpci(pdev, candev);
			if(cnt == -1) {
			    DBGOUT();
			    return -EBUSY;
			}
			candev += cnt;
			}
		}
		if (pdev->vendor == PCI_VENDOR_CAN_EMS
			&& pdev->device == PCI_DEVICE_CAN) {
		    pr_info("found old EMS PCI board V1 %s", pci_name(pdev));
		    if (pci_enable_device(pdev))
			    continue;
		    else {
			int cnt;
			cnt = register_v1_cpcpci(pdev, candev);
			if(cnt == -1) {
			    DBGOUT();
			    return -EBUSY;
			}
			candev += cnt;
		    }
		}
	}
	if (candev == 0) {
	    pr_err("No CAN device found");
	    DBGOUT();
	    return -ENODEV;
	} else
	    pr_info("found %d CAN controllers", candev);

	DBGOUT();
	return 0;
}

/* Called from __init,  once when driver is loaded
   set up physical addresses, irq number
   and initialize clock source for the CAN module

   Take care it will be called only once
   because it is called for every CAN channel out of MAX_CHANNELS
*/
int init_board_hw(int n)
{
static int already_called = 0;
int ret;
int minor = -1;

    DBGIN();
    ret = 0;
    if (!already_called && virtual == 0) {
	/* make some sysctl entries read only
	 * IRQ number
	 * Base address
	 * and access mode
	 * are fixed and provided by the PCI BIOS
	 */
	can_sysctl_table[CAN_SYSCTL_IRQ - 1].mode = 0444;
	can_sysctl_table[CAN_SYSCTL_BASE - 1].mode = 0444;
	/* printk(KERN_INFO "CAN pci test loaded\n"); */
	/* proc_dbgmask = 0; */
	if (pcimod_scan()) {
	    pr_err("no valid PCI CAN found");
	    ret = -EIO;
	} else
	    pr_info("\tpci scan success");
	already_called = 1;
    }
    DBGOUT();
    return ret;
}


void exit_board_hw(void)
{
#if 0
int i;
#endif
int minor = -1;
    DBGIN();
    /* release the board(s) from this driver  */


#if 0
    /* we have a maximum of supported CAN channels with this driver
     * in theory, every CAN Channel can belong to a different board
     * in case of boards with only one channel.
     * Therefore a test of the address to the address space
     * is necessary and because of the different layout  of the PCI BAR
     * also a test of the version of the EMS board's hardware */


    /* BUT, if we have more than one board, which board is it?
     * which minors belongs to it ? */

    for(i = 0; i < MAX_CHANNELS; i++) {
	pci_release_region(can_pitapci_control[i], 0);
	if(ems_card_version[minor] == 1) {
	    pci_release_region(can_pitapci_control[i], EMS_PCI_V1_BASE_BAR);
	} else {
	    pci_release_region(can_pitapci_control[i], EMS_PCI_V2_BASE_BAR);
	}
    }
------------
     /* there is another call, releasing all regions related to pdev */
    for(i = 0; i < MAX_CHANNELS; i++) {
	if(can_pitapci_control[i] != NULL)
	    pci_release_regions(can_pitapci_control[i]);
    }
#else
#endif
    DBGOUT();
}

int can_requestirq(int minor, int irq, irqreturn_t (*handler)(int, void *))
{
int err;

	DBGIN();
	/*

	int request_irq(unsigned int irq,			// interrupt number
	void (*handler)(int, void *, struct pt_regs *), // pointer to ISR
	      irq, dev_id, registers on stack
	unsigned long irqflags, const char *devname,
	void *dev_id);

	dev_id - The device ID of this handler (see below).
	This parameter is usually set to NULL,
	but should be non-null if you wish to do  IRQ  sharing.
	This  doesn't  matter when hooking the
	interrupt, but is required so  that,  when  free_irq()  is
	called,  the  correct driver is unhooked.  Since this is a
	void *, it can point to anything (such  as  a  device-spe-
	cific  structure,  or even empty space), but make sure you
	pass the same pointer to free_irq().

	*/

	err = request_irq(irq, handler, IRQF_SHARED, "can4linux", &can_minors[minor]);


	if (!err) {
		DBGPRINT(DBG_BRANCH, ("Requested IRQ: %d @ 0x%lx",
			irq, (unsigned long)handler));
		irq_requested[minor] = 1;
	}
	DBGOUT();
	return err;
}


int can_freeirq(int minor, int irq)
{
	DBGIN();
	irq_requested[minor] = 0;
	/* pr_info(" Free IRQ %d  minor %d\n", irq, minor);  */
	free_irq(irq, &can_minors[minor]);
	DBGOUT();
	return 0;
}

/*
 * Perform Vendor-Init, that means sometimes CAN controller
 * or only board manufacturer specific initialization.
 *
 * Mainly it gets needed IO and IRQ ressources and initilaizes
 * special hardware functions.
 *
 */

int can_vendor_init(int minor)
{
	DBGIN();
	can_range[minor] = CAN_RANGE;

	/* PCI scan for CPC-PCI (or others ) has already remapped the address */
	/* pr_info(" assign address direct\n"); */
	can_iobase[minor] = (void __iomem *)proc_base[minor];

	/* The Interrupt Line is already requested by the PC CARD Services
	* (in case of CPC-Card: cpc-card_cs.c)
	*/

	/* pr_info("MAX_IRQNUMBER %d/IRQ %d\n", MAX_IRQNUMBER, IRQ[minor]); */
	if (IRQ[minor] > 0 && IRQ[minor] < MAX_IRQNUMBER) {
		if (can_requestirq(minor, IRQ[minor], can_interrupt)) {
			pr_err("Can[%d]: Can't request IRQ %d\n",
					minor, IRQ[minor]);
			DBGOUT();
			return -EBUSY;
		}
	} else {
		/* Invalid IRQ number in /proc/.../IRQ */
		DBGOUT();
		return -EINVAL;
	}
	DBGOUT();
	return 0;
}

/* check memory region if there is a CAN controller
*  assume the controller was resetted before testing
*
*  The check for an available controller is difficult !
*  After an Hardware Reset (or power on) the Controller
*  is in the so-called 'BasicCAN' mode.
*     we can check for:
*        address  name      value
*	    0x00  mode       0x21
*           0x02  status     0xc0
*           0x03  interrupt  0xe0
* Once loaded the driver switches into 'PeliCAN' mode and things are getting
* difficult, because we now have only a 'soft reset' with not so  unique
* values. The values have to be masked before comparing.
*        address  name       mask   value
*	    0x00  mode
*           0x01  command    0xff    0x00
*           0x02  status     0x37    0x34
*           0x03  interrupt  0xfb    0x00
*
* EMS is using a different approach in the SocketCAN driver
* by trying to set 'em into the PeliCAN mode and try to read back the same value
* ems_pci_check_chan()
*
*
*
*
*
*/
int controller_available(void __iomem *address, int offset)
{
void __iomem *ptr = address;

	pr_info("controller_available 0x%p\n", address);

#if 0     /* debugging */
	pr_info("0x%0x, ", readb(ptr));
	pr_info("0x%0x, ", readb(ptr + (2 * offset)));
	pr_info("0x%0x\n", readb(ptr + (3 * offset)));

	/* return 1; */
#endif

#define CDR_PELICAN     0x80 /* PeliCAN mode */
	/* aus SocketCAN plx_pci.c */
/* States of some SJA1000 registers after hardware reset in the BasicCAN mode*/
#define REG_CR_BASICCAN_INITIAL		0x21
#define REG_CR_BASICCAN_INITIAL_MASK	0xa1
#define REG_SR_BASICCAN_INITIAL		0x0c
#define REG_IR_BASICCAN_INITIAL		0xe0

/* States of some SJA1000 registers after hardware reset in the PeliCAN mode*/
#define REG_MOD_PELICAN_INITIAL		0x01
#define REG_SR_PELICAN_INITIAL		0x3c
#define REG_IR_PELICAN_INITIAL		0x00

	/* first byte after hard reset 0x21 or 0x3f ?? */
	if (0x21 == (readb(ptr) & 0xa1)) {
		/* compare reset values of status and interrupt register */
		if (0x0c == readb(ptr + (2 * offset))
			&& 0xe0 == readb(ptr + (3 * offset))) {
			pr_info("\ttrue with first test\n");
			return 1;
		} else {
			return 0;
		}
	} else {
		/* may be called after a 'soft reset' in 'PeliCAN' mode */
		/*   value     address                     mask    */
		if (0x00 ==  readb(ptr + (1 * offset))
			&& 0x34 == (readb(ptr + (2 * offset))    & 0x37)
			&& 0x00 == (readb(ptr + (3 * offset))    & 0xfb)) {
			pr_info("\ttrue with second test\n");
			return 1;
		} else {
			return 0;
		}
	}
}

#if 0
static struct pci_device_id  ems_pci_tbl[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030), },
	{ 0, },                 /* End of list */
};
#endif







void board_clear_interrupts(int minor)
{

/* we need a proc variable for the version, v1 or V2 */

   if(ems_card_version[minor] == 1) {
	/* old  Siemens PITA V1 */
	/* Interrupt_0_Enable (bit 17) + Int_0_Reset (bit 1) */
	writel(0x00020002, (void __iomem *)can_pitapci_control[minor] + 0x0);
	writel(0x00020000, (void __iomem *)can_pitapci_control[minor] + 0x0);
   } else {
	/* new V2

	writel(PLX9030_ICR_CLEAR_IRQ0 | PLX9030_ICR_ENABLE_IRQ0,
	(void __iomem *)can_pitapci_control[minor] + PLX9030_ICR);
	 * */
	writel(PLX_ICSR_ENA_CLR,
		(void __iomem *)can_pitapci_control[minor] + PLX_ICSR);
   }
}
